const createPallete = (palette) => {
    const colors = palette.split('_');
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const res = [];

    colors.forEach((c) => {
        ctx.fillStyle = c;
        ctx.clearRect(0, 0, 1, 1);
        ctx.fillRect(0, 0, 1, 1);

        const imageData = ctx.getImageData(0, 0, 1, 1);

        res.push({
            r: imageData.data[0],
            g: imageData.data[1],
            b: imageData.data[2],
        });
    });

    return res;
};
function ditheringFilter(imageData, palette) {
    if (!palette) {
        palette = [
            { r: 255, g: 255, b: 255 },
            { r: 0, g: 0, b: 0 },
        ];
    } else {
        palette = createPallete(palette);
    }
    const w = imageData.width;
    const h = imageData.height;
    const data = imageData.data;

    for (let i = 0; i < data.length; i += 4) {
        const r = data[i];
        const g = data[i + 1];
        const b = data[i + 2];
        const c = getClosestColor({ r, g, b }, palette);

        data[i] = c.r;
        data[i + 1] = c.g;
        data[i + 2] = c.b;

        const delta = sub({ r, g, b }, c);
        const x = (i / 4) % w;
        const y = Math.floor(i / 4 / w);

        if (x + 1 < w) refresh(data, i + 4, mul(delta, 7 / 16));
        if (x - 1 > 0 && y + 1 < h)
            refresh(data, i + 4 * w - 4, mul(delta, 3 / 16));
        if (y + 1 < h) refresh(data, i + 4 * w, mul(delta, 5 / 16));
        if (x + 1 < w && y + 1 < h)
            refresh(data, i + 4 * w + 4, mul(delta, 1 / 16));
    }

    return imageData;
}

function getClosestColor(c, palette) {
    let closestColor = palette[0];
    let closest = diff(c, palette[0]);

    for (let i = 1; i < palette.length; i++) {
        const d = diff(c, palette[i]);
        if (d < closest) {
            closest = d;
            closestColor = palette[i];
        }
    }

    return closestColor;
}

function diff(c1, c2) {
    return Math.abs(c1.r - c2.r) + Math.abs(c1.g - c2.g) + Math.abs(c1.b - c2.b);
}

function refresh(data, i, dc) {
    data[i] += dc.r;
    data[i + 1] += dc.g;
    data[i + 2] += dc.b;
}

function sub(c1, c2) {
    return {
        r: c1.r - c2.r,
        g: c1.g - c2.g,
        b: c1.b - c2.b,
    };
}

function mul(c, k) {
    return {
        r: c.r * k,
        g: c.g * k,
        b: c.b * k,
    };
}

export default ditheringFilter;
